package at.fhj.ase.business;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.Characters;
import javax.xml.stream.events.EndElement;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;

import org.codehaus.stax2.XMLInputFactory2;

import com.ctc.wstx.api.ReaderConfig;

import at.fhj.ase.data.Filter;

/**
 * 
 * @author Zandmiralvand, Mansouri, Jaklitsch
 * 
 * This class reads the filters file and creates filter objects for the XML tags
 *
 */
public class FilterParser {
	
	private Filter currentFilter;
	private StartElement currentElement;
	private List<String> tags;
	
//	/////////Default Constructor//////
//	public FilterParser(){
//		return;
//	}
//	/////////////////////////	
//	////constructor///
//	public FilterParser(Filter currentFilter, StartElement currentElement,List<String> tags){
//		setFilterParser(currentFilter, currentElement, tags);
//	} 
//	
//	private void setFilterParser(Filter currentFilter,
//			StartElement currentElement, List<String> tags) {
//		// TODO Auto-generated method stub
//		this.currentElement= currentElement;
//		this.currentFilter=currentFilter;
//		this.tags=tags;
//		
//	}
	////////////////////
	public XMLEventReader createFilterFileParser() throws FileNotFoundException, IOException, XMLStreamException{
		
		Properties props = new Properties();
		props.load(new FileInputStream("resources/application.properties"));
		String filtersFile = props.getProperty("filter.file");
		InputStream in = new FileInputStream(filtersFile);
		
		//TODO: set the factory to validating and the XMLReporter for handling XML schema validation
		
		//use a different StAX parser
		System.setProperty("javax.xml.stream.XMLInputFactory", "com.ctc.wstx.stax.WstxInputFactory");
//		System.setProperty("javax.xml.stream.XMLOutputFactory", "com.ctc.wstx.stax.WstxEventFactory");
		System.setProperty("javax.xml.stream.XMLEventFactory", "com.ctc.wstx.stax.WstxOutputFactory");

		
		XMLInputFactory factory = XMLInputFactory.newInstance();
		factory.setProperty(XMLInputFactory2.P_REPORT_CDATA, Boolean.TRUE);
		XMLEventReader parser = factory.createXMLEventReader(in);
		return parser;
	}
	
	public List<Filter> extractFilters(XMLEventReader parser) throws XMLStreamException {
		if(parser == null)
			throw new IllegalArgumentException("parser may not be null");
		
		List<Filter> filters = new ArrayList<Filter>();
		
		while (parser.hasNext()){
			
			XMLEvent event = parser.nextEvent();
			String elementName = null;

			switch (event.getEventType())
			{
			case XMLEvent.END_DOCUMENT:
				parser.close();
				break;
			case XMLEvent.START_ELEMENT:
				currentElement = event.asStartElement();
				elementName = currentElement.getName().getLocalPart();
				if(elementName.equals("filter"))
				{
					currentFilter = new Filter();
				}
				else if (elementName.equals("id")){
					processId(parser);
				}
				else if (elementName.equals("description")){
					processDescription(parser);
				}
				else if(elementName.equals("impact")){
					processImpact(parser);
				}
				else if(elementName.equals("rule")){
					parser.nextEvent(); //skip the whitespace before the CDATA section
					processRule(parser);
				}
				else if(elementName.equals("tag")){
					processTag(parser);
				}
				break;
			case XMLEvent.CHARACTERS:
				break;
			case XMLEvent.END_ELEMENT:
				EndElement endElement = event.asEndElement();
				if(endElement.getName().getLocalPart().equals("filter"))
				{
					//add filter to the list
					filters.add(currentFilter);
					System.out.println(currentFilter);
				}
				break;
			default :
				break;
			}

		}
		return filters;
	}

	private void processId(XMLEventReader parser) throws XMLStreamException {
		Characters idChars = parser.nextEvent().asCharacters();
		Integer id = Integer.parseInt(idChars.getData());
		currentFilter.setId(id);
		
	}

	private void processTag(XMLEventReader parser) throws XMLStreamException {
			Characters tagChars = parser.nextEvent().asCharacters();
		currentFilter.addTag(tagChars.getData());
	}

	private void processRule(XMLEventReader parser) throws XMLStreamException {
		currentFilter.setFilterRule(parser.nextEvent().asCharacters().getData());
		
	}

	private void processImpact(XMLEventReader parser) throws XMLStreamException {
		Characters impactChars = parser.nextEvent().asCharacters();
		Integer impact = Integer.parseInt(impactChars.getData());
		currentFilter.setImpact(impact);
		
	}

	private void processDescription(XMLEventReader parser) throws XMLStreamException {
		Characters descriptionChars = parser.nextEvent().asCharacters();
		currentFilter.setDescription(descriptionChars.getData());		
	}

}
